﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace IngressLinker
{
    struct popopo
    {
        public UIElement a;
        public int count;
    }

    public partial class MainWindow : Window
    {
        static popopo popopo1 = new popopo();
        static popopo popopo2 = new popopo();
        static popopo popopo3 = new popopo();
        private List<Ellipse> twoFirst = new List<Ellipse>();

        Controller c;
        public MainWindow()
        {
            InitializeComponent();
            //Uri iconUri = new Uri("pack://siteoforigin:,,,/Resources/favicon.ico", UriKind.RelativeOrAbsolute);
            //this.Icon = BitmapFrame.Create(iconUri);
            c = new Controller();
            c.Changed += new ChangedEventHandler(ListChanged);
        }

        private void LoadButton_Click(object sender, RoutedEventArgs e)
        {
            c.LoadFile();
        }

        private void ReloadButton_Click(object sender, RoutedEventArgs e)
        {
            c.ReloadFile();
        }

        public void ListChanged(List<Point> points)
        {
            this.ReloadButton.IsEnabled = true;
            this.GetLinkButton.IsEnabled = true;
            this.MainGrid.Children.RemoveRange(0, MainGrid.Children.Count);

            double Xmin = points[0].X, Ymin = points[0].Y, Xmax = points[0].X, Ymax = points[0].Y;
            foreach (Point p in points)
            {
                if (p.X > Xmax) Xmax = p.X;
                if (p.X < Xmin) Xmin = p.X;
                if (p.Y > Ymax) Ymax = p.Y;
                if (p.Y < Ymin) Ymin = p.Y;
            }
            List<Point> use2first = new List<Point>();
            if (Use2first.IsChecked == true)
            {
                use2first.Add(points[0]);
                use2first.Add(points[1]);
            }
                

            Point center = new Point((Xmax + Xmin) / 2, (Ymax + Ymin) / 2);
            double max = Math.Min(MainGrid.ActualWidth, MainGrid.ActualHeight);
            double dmax = Math.Max(Math.Max(Math.Abs(center.X - Xmax), Math.Abs(center.X - Xmin)), Math.Max(Math.Abs(center.Y - Ymax), Math.Abs(center.Y - Ymin)));
            double m = max / dmax;
            foreach (Point p in points)
            {
                double x = (center.X - p.X) * m;
                double y = (p.Y - center.Y) * m;
                Ellipse myEllipse = new Ellipse();
                myEllipse.Tag = p;
                myEllipse.StrokeThickness = 3;
                myEllipse.Stroke = Brushes.Black;
                myEllipse.Width = 10;
                myEllipse.Height = 10;
                myEllipse.Margin = new Thickness(y, x, 0, 0);
                myEllipse.ToolTip = string.Format("{0};{1}", p.X, p.Y);
                MainGrid.Children.Add(myEllipse);
                if (use2first.Contains(p))
                    twoFirst.Add(myEllipse);
            }

            CalculateFirst();
        }

        private void CalculateFirst()
        {
            List<UIElement> tempArray = new List<UIElement>();
            foreach (UIElement ui in MainGrid.Children)
            {
                if (ui is Ellipse)
                    tempArray.Add(ui);
            }

            List<UIElement> BestLines = new List<UIElement>();
            if (Use2first.IsChecked == true)
            {
                popopo _popopo = FindOptiomal(tempArray, twoFirst[0], twoFirst[1]);
                BestLines = new List<UIElement>() { twoFirst[0], twoFirst[1], _popopo.a };
            }
            else
            {
                int count = 0;
                foreach (UIElement ui1 in MainGrid.Children)
                {
                    if (!(ui1 is Ellipse))
                        continue;
                    foreach (UIElement ui2 in MainGrid.Children)
                    {
                        if (!(ui2 is Ellipse))
                            continue;
                        popopo _popopo = FindOptiomal(tempArray, ui1, ui2);
                        if (_popopo.count > count)
                        {
                            count = _popopo.count;
                            BestLines = new List<UIElement>() { ui1, ui2, _popopo.a };
                        }
                    }
                }
            }
            
            MainGrid.Children.Add(DrawLine(BestLines[0], BestLines[1]));
            MainGrid.Children.Add(DrawLine(BestLines[1], BestLines[2]));
            MainGrid.Children.Add(DrawLine(BestLines[0], BestLines[2]));

            // hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh

            Recursion(tempArray, BestLines);
        }

        private void Recursion(List<UIElement> all, List<UIElement> BestLines)
        {
            List<UIElement> newArray = new List<UIElement>();
            foreach (UIElement ui in all)
            {
                if (!Check(ui, BestLines[0], BestLines[1], BestLines[2]))
                {
                    newArray.Add(ui);
                }
            }
            foreach (UIElement ui in newArray)
            {
                all.Remove(ui);
            }
            GC.SuppressFinalize(newArray);
            if (Use2first.IsChecked == true)
            {
                popopo1 = FindOptiomal(all, BestLines[0], BestLines[1]);
                BestLines = new List<UIElement>() { BestLines[0], BestLines[1], popopo1.a };
            }
            else
            {
                popopo1 = FindOptiomal(all, BestLines[0], BestLines[1]);
                popopo2 = FindOptiomal(all, BestLines[0], BestLines[2]);
                popopo3 = FindOptiomal(all, BestLines[2], BestLines[1]);

                int maxCount = Math.Max(Math.Max(popopo1.count, popopo2.count), popopo3.count);

                if ((popopo1.count >= popopo2.count) && (popopo1.count >= popopo3.count))
                    BestLines = new List<UIElement>() { BestLines[0], BestLines[1], popopo1.a };
                else if ((popopo2.count >= popopo1.count) && (popopo2.count >= popopo3.count))
                    BestLines = new List<UIElement>() { BestLines[0], BestLines[2], popopo2.a };
                else if ((popopo3.count >= popopo1.count) && (popopo3.count >= popopo2.count))
                    BestLines = new List<UIElement>() { BestLines[1], BestLines[2], popopo3.a };
            }

            
            Line a = new Line();
            a = DrawLine(BestLines[0], BestLines[1]);
            if (a != null)
                MainGrid.Children.Add(a);
            a = DrawLine(BestLines[1], BestLines[2]);
            if (a != null)
                MainGrid.Children.Add(a);
            a = DrawLine(BestLines[0], BestLines[2]);
            if (a != null)
                MainGrid.Children.Add(a);

            if (all.Count > 2)
                Recursion(all, BestLines);
        }

        private popopo FindOptiomal(List<UIElement> all, UIElement ui1, UIElement ui2)
        {
            popopo popopo1 = new popopo() { count = 0 };
            
            foreach (UIElement ui3 in all)
            {
                if (!(ui3 is Ellipse))
                    continue;
                int tempcount = 0;
                foreach (UIElement ui0 in all)
                {
                    if (!(ui0 is Ellipse))
                        continue;
                    bool flag = false;
                    flag = Check(ui0, ui1, ui2, ui3);
                    if (flag)
                        tempcount++;
                }
                if (tempcount > popopo1.count)
                {
                    popopo1 = new popopo() { a = ui3, count = tempcount };
                }
            }

            return popopo1;
        }

        private Line DrawLine(UIElement uia, UIElement uib)
        {
            if ((uia == null) || (uib == null))
                return null;
            Line templine = new Line();
            templine.Tag = new List<object>() { (uia as Ellipse).Tag, (uib as Ellipse).Tag };
            templine.X1 = ((uia as Ellipse).Margin.Left + MainGrid.ActualWidth) / 2;
            templine.X2 = ((uib as Ellipse).Margin.Left + MainGrid.ActualWidth) / 2;
            templine.Y1 = ((uia as Ellipse).Margin.Top + MainGrid.ActualHeight) / 2;
            templine.Y2 = ((uib as Ellipse).Margin.Top + MainGrid.ActualHeight) / 2;
            templine.StrokeThickness = Convert.ToInt32(Thickness.Text);
            if (Colorize.IsChecked == true)
            {
                Random rnd = new Random();
                byte r = (byte)rnd.Next(200);
                Thread.Sleep(100);
                byte g = (byte)rnd.Next(200);
                Thread.Sleep(100);
                byte b = (byte)rnd.Next(200);
                templine.Stroke = new SolidColorBrush(Color.FromRgb(r, g, b));
            }
            else
                templine.Stroke = Brushes.Black;
            
            return templine;
        }

        private bool Check(UIElement ui0, UIElement ui1, UIElement ui2, UIElement ui3)
        {
            List<double> ch = new List<double> { (ui0 as Ellipse).Margin.Left, (ui1 as Ellipse).Margin.Left, (ui2 as Ellipse).Margin.Left, (ui3 as Ellipse).Margin.Left };
            if (ch.Distinct().Count() != ch.Count())
                return false;
            GC.SuppressFinalize(ch);
            double a = ((ui1 as Ellipse).Margin.Left - (ui0 as Ellipse).Margin.Left) * ((ui2 as Ellipse).Margin.Top - (ui1 as Ellipse).Margin.Top) - ((ui2 as Ellipse).Margin.Left - (ui1 as Ellipse).Margin.Left) * ((ui1 as Ellipse).Margin.Top - (ui0 as Ellipse).Margin.Top);
            double b = ((ui2 as Ellipse).Margin.Left - (ui0 as Ellipse).Margin.Left) * ((ui3 as Ellipse).Margin.Top - (ui2 as Ellipse).Margin.Top) - ((ui3 as Ellipse).Margin.Left - (ui2 as Ellipse).Margin.Left) * ((ui2 as Ellipse).Margin.Top - (ui0 as Ellipse).Margin.Top);
            double c = ((ui3 as Ellipse).Margin.Left - (ui0 as Ellipse).Margin.Left) * ((ui1 as Ellipse).Margin.Top - (ui3 as Ellipse).Margin.Top) - ((ui1 as Ellipse).Margin.Left - (ui3 as Ellipse).Margin.Left) * ((ui3 as Ellipse).Margin.Top - (ui0 as Ellipse).Margin.Top);

            return (a >= 0 && b >= 0 && c >= 0) || (a <= 0 && b <= 0 && c <= 0);
        }

        private void GetLinkButton_Click(object sender, RoutedEventArgs e)
        {
            string link = @"http://www.ingress.com/intel?pls=";
            List<Line> addedLines = new List<Line>();
            List<object> tagFromLine;
            foreach(UIElement portal in MainGrid.Children)
            {
                if (portal is Line)
                {
                    Line l = portal as Line;
                    tagFromLine = l.Tag as List<object>;
                    if ((addedLines.Count == 0) || (addedLines.Count > 0 && addedLines.Find(x => (x.Tag as List<object>).Contains(tagFromLine[0]) && (x.Tag as List<object>).Contains(tagFromLine[1])) == null))
                    {
                        Point a = (Point)(l.Tag as List<object>)[0];
                        Point b = (Point)(l.Tag as List<object>)[1];
                        link = string.Format("{0}{1},{2},{3},{4}_", link, a.X.ToString().Replace(",", "."), a.Y.ToString().Replace(",", "."), b.X.ToString().Replace(",", "."), b.Y.ToString().Replace(",", "."));
                        addedLines.Add(l);
                    }                    
                }
            }
            link = link.TrimEnd(new[]{'_'});

            LinkWindow lw = new LinkWindow(link);
            lw.Show();
        }
    }
}
